package com.shiliuzi.www.util.excelUtil;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.shiliuzi.www.common.Code;
import com.shiliuzi.www.exception.GlobalException;
import com.shiliuzi.www.mapper.DownloadMapper;
import com.shiliuzi.www.pojo.bo.util.DownloadExcelReadBo;
import com.shiliuzi.www.pojo.bo.util.DownloadExcelUserBo;
import com.shiliuzi.www.pojo.dto.download.DownloadExcelDto;
import com.shiliuzi.www.pojo.dto.download.util.DownloadExcelTypeUtil;
import com.shiliuzi.www.pojo.dto.download.util.DownloadExcelUserUtil;
import com.shiliuzi.www.pojo.po.User;
import com.shiliuzi.www.util.CommonUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Excel表格读取
 */
@Slf4j
@Service
public class ExcelReadUtil {

    @Resource
    private DownloadMapper downloadMapper;

    @Resource
    private CommonUtil commonUtil;

    private static List<DownloadExcelDto> excelSource = new ArrayList<>();

    /**
     * 读取excel监听器
     */
    @AllArgsConstructor
    private class ExcelReadListener extends AnalysisEventListener<DownloadExcelDto> {

        private String fileName;

        @Override
        public void invoke(DownloadExcelDto downloadExcelDto, AnalysisContext analysisContext) {
            downloadExcelDto.setPathFile(fileName);
            excelSource.add(downloadExcelDto);
            log.info("正在读取Record数据的编号是：{}", JSON.toJSON(downloadExcelDto));
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            log.info("读取完毕！");
        }
    }

    /**
     * 核心读取方法
     * @param multipartFile
     * @return
     */
    public List<DownloadExcelDto> readRecord(MultipartFile multipartFile) {
        String fileName = multipartFile.getOriginalFilename();

        if (!processFormat(fileName)) return null;

        try {
            EasyExcel.read(multipartFile.getInputStream(),new ExcelReadListener(fileName))
                    .head(DownloadExcelDto.class)
                    .sheet()
                    .doRead();
            return excelSource;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 后缀判断处理器
     * @param fileName
     * @return
     */
    private boolean processFormat(String fileName) {
        String fileSuffix = fileName.substring(fileName.lastIndexOf(".") + 1);

        if (fileSuffix.equals("xls") || fileSuffix.equals("xlsx")) return true;
        return false;
    }

    /**
     * 设置合法性判断
     * @param source
     * @return
     */
    public List<DownloadExcelReadBo> judgeLegality(List<DownloadExcelDto> source) {

        if (source == null || source.size() == 0) return null;

        List<DownloadExcelReadBo> returnTarget = new ArrayList<>();

        for(DownloadExcelDto downloadExcelDto : source) {

            //1、迭代信息是否为空
            downloadExcelDto = judgeSingleIsNull(downloadExcelDto);

            //2、判断学号是否合法
            boolean numberJudge = judgeNumberIsLegal(downloadExcelDto);

            //3、奖惩类型是否为奖励和惩罚
            boolean typeJudge = judgeTypeIsLegal(downloadExcelDto);

            //4、奖惩类别是否存在
            Integer isRight = 1;

            Integer classId = judgeAndReturnType(downloadExcelDto,numberJudge,typeJudge);
            if (classId <= 0) isRight = 0;

            //5、名字是否重名，是则拼接姓名，且判断是否有这个人
            DownloadExcelUserBo downloadExcelUserBo = judgeAndReturnUser(source, downloadExcelDto);
            if (downloadExcelUserBo == null) {
                isRight = 0;
                downloadExcelUserBo = new DownloadExcelUserBo(0,downloadExcelDto.getUserName(),downloadExcelDto.getNumber(),0);
            }

            //6、重新载入可写入数据库类型
            returnTarget.add(new DownloadExcelReadBo(
                    classId,
                    downloadExcelUserBo,
                    downloadExcelDto.getPathFile(),
                    isRight,
                    downloadExcelDto));
        }

        return returnTarget;
    }

    /**
     * 迭代信息处理器
     * @param downloadExcelDto
     * @return
     */
    private DownloadExcelDto judgeSingleIsNull(DownloadExcelDto downloadExcelDto) {
        Class classTarget = downloadExcelDto.getClass();

        Field[] fields = classTarget.getDeclaredFields();
        try {
            for (Field field : fields) {
                if (!field.getType().equals(String.class) || field.getName().equals("comment")) continue;

                String fieldName = field.getName();
                String suffix = fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);

                Method methodTarget = classTarget.getDeclaredMethod("get" + suffix);

                Object invoke = methodTarget.invoke(downloadExcelDto);
                if (invoke != null) continue;

                methodTarget = classTarget.getDeclaredMethod("set" + suffix, String.class);
                methodTarget.invoke(downloadExcelDto,"未填写");
            }
            return downloadExcelDto;
        } catch (Exception e) {
            throw new GlobalException(Code.SYS_ERR,"系统内部出错！迭代信息处理器宕机！");
        }
    }

    /**
     * 学号校验处理器
     * @param downloadExcelDto
     * @return
     */
    private boolean judgeNumberIsLegal(DownloadExcelDto downloadExcelDto) {
        String number = downloadExcelDto.getNumber();
        String pattern = "^3\\d{3}00\\d{4}$";

        if (number == null) return false;
        if(!number.matches(pattern)) return false;

        return true;
    }

    /**
     * 类型限定校验处理器
     * @param downloadExcelDto
     * @return
     */
    private boolean judgeTypeIsLegal(DownloadExcelDto downloadExcelDto) {
        String type = downloadExcelDto.getType();

        return type.equals("奖励") || type.equals("惩罚");
    }

    /**
     * 类别限制返回处理器
     * @param downloadExcelDto
     * @return
     */
    private Integer judgeAndReturnType(DownloadExcelDto downloadExcelDto, boolean numberJudge, boolean typeJudge) {

        if (numberJudge && !typeJudge) return -1;

        String type = downloadExcelDto.getType();
        DownloadExcelTypeUtil downloadExcelTypeUtil = new DownloadExcelTypeUtil(downloadExcelDto.getTypeContent());

        if (type.equals("奖励")) downloadExcelTypeUtil.setType(1);
        else downloadExcelTypeUtil.setType(0);

        return downloadMapper.obtainTypeId(downloadExcelTypeUtil);
    }

    /**
     * 用户限制返回处理器
     * @param downloadExcelDto
     * @return
     */
    private DownloadExcelUserBo judgeAndReturnUser(List<DownloadExcelDto> source, DownloadExcelDto downloadExcelDto) {
        String number = downloadExcelDto.getNumber();
        String userName = downloadExcelDto.getUserName();

        for (DownloadExcelDto singleValue : source) {
            String name = downloadExcelDto.getUserName();

            if (downloadExcelDto == singleValue) continue;
            if (!singleValue.getUserName().equals(userName) && !singleValue.getNumber().equals(number)) continue;

            downloadExcelDto.setUserName(name + downloadExcelDto.getNumber());
            break;
        }

        User user = downloadMapper.obtainUser(new DownloadExcelUserUtil(number, userName));
        return commonUtil.copyProperties(user, DownloadExcelUserBo.class);
    }
}
